home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
lib
/
c
/
etc
/
RCS
/
ttyPdev.c,v
< prev
next >
Wrap
Text File
|
1990-02-28
|
21KB
|
788 lines
head 1.8;
branch ;
access ;
symbols ;
locks ; strict;
comment @ * @;
1.8
date 90.02.28.11.10.55; author brent; state Exp;
branches ;
next 1.7;
1.7
date 89.06.29.16.24.23; author ouster; state Exp;
branches ;
next 1.6;
1.6
date 89.06.15.15.09.37; author ouster; state Exp;
branches ;
next 1.5;
1.5
date 89.06.03.16.47.26; author ouster; state Exp;
branches ;
next 1.4;
1.4
date 89.06.02.13.38.39; author brent; state Exp;
branches ;
next 1.3;
1.3
date 89.04.20.10.24.21; author ouster; state Exp;
branches ;
next 1.2;
1.2
date 89.04.20.10.23.14; author ouster; state Exp;
branches ;
next 1.1;
1.1
date 89.04.20.10.04.16; author ouster; state Exp;
branches ;
next ;
desc
@@
1.8
log
@Updated to new Td_ControlCooked interface
@
text
@/*
* ttyPdev.c --
*
* This file provides a bridge between the pdev and td modules to
* produce a pseudo-device that behaves like a terminal.
*
* Copyright 1989 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyPdev.c,v 1.7 89/06/29 16:24:23 ouster Exp Locker: brent $ SPRITE (Berkeley)";
#endif /* not lint */
#include <pdev.h>
#include <status.h>
#include <stdlib.h>
#include <string.h>
#include <td.h>
/*
* Library imports:
*/
extern void panic();
/*
* One of the following structures is created for each call to
* Td_CreatePdev:
*/
typedef struct {
Pdev_Token pdev; /* Token returned by Pdev_Open. */
char *pdevName; /* Name of pseudo-device file
* (malloc'ed). */
Td_Terminal term; /* Token returned by Td_Create. */
int selectState; /* Current select state of terminal;
* a combination of FS_READABLE,
* FS_WRITABLE, and FS_EXCEPTION. */
} PdevTerm;
/*
* Forward declarations to procedures defined later in this file:
*/
static int ChangeReady();
static int CookedProc();
static int PdevClose();
static int PdevIoctl();
static int PdevOpen();
static int PdevRead();
static int PdevWrite();
static int SendSignal();
/*
*----------------------------------------------------------------------
*
* Td_CreatePdev --
*
* Create a terminal with a pseudo-device attached to it.
*
* Results:
* The return value is a handle that may be passed to
* Td_DeletePdev to close the pseudo-terminal. The Td_Terminal
* token for the terminal gets stored at *termPtr, for the
* caller's use in communicating with the terminal driver.
* If a pseudo-device couldn't be opened, then the return value
* is NULL and an error message is stored in pdev_ErrorMsg.
*
* Side effects:
* A Td_Terminal is created with its "cooked" side attached
* to a pseudo-device managed by this module. The caller
* must use the Fs_Select facilities so that this module
* gets callbacks from the Pdev library.
*
*----------------------------------------------------------------------
*/
Td_Pdev
Td_CreatePdev(name, realNamePtr, termPtr, rawProc, clientData)
char *name; /* Name of file to use for pseudo-device. */
char **realNamePtr; /* Where to store pointer to actual name
* used. */
Td_Terminal *termPtr; /* Token for the Td_Terminal gets written
* here, if this is non-NULL. */
int (*rawProc)(); /* Procedure for Td module to call to
* handle control requests on raw side
* of terminal. */
ClientData clientData; /* Arbitrary data value to pass to rawProc. */
{
Pdev_CallBacks callbacks;
register PdevTerm *ptPtr;
ptPtr = (PdevTerm *) malloc(sizeof(PdevTerm));
callbacks.open = PdevOpen;
callbacks.read = PdevRead;
callbacks.write = PdevWrite;
callbacks.ioctl = PdevIoctl;
callbacks.close = PdevClose;
ptPtr->pdev = Pdev_Open(name, realNamePtr, 1000, 0,
&callbacks, (ClientData) ptPtr);
if (ptPtr->pdev == NULL) {
free((char *) ptPtr);
return (Td_Pdev) NULL;
}
if (realNamePtr != NULL) {
name = *realNamePtr;
}
ptPtr->pdevName = malloc((unsigned) (strlen(name) + 1));
strcpy(ptPtr->pdevName, name);
ptPtr->term = Td_Create(1000, CookedProc, (ClientData) ptPtr,
rawProc, clientData);
ptPtr->selectState = FS_WRITABLE;
if (termPtr != NULL) {
*termPtr = ptPtr->term;
}
return (Td_Pdev) ptPtr;
}
/*
*----------------------------------------------------------------------
*
* Td_DeletePdev --
*
* Delete a pseudo-device and the Td_Terminal associated with it.
*
* Results:
* None.
*
* Side effects:
* The memory and state associated with the pseudo device and
* terminal are recycled. The pseudo-device file is destroyed,
* if that is possible.
*
*----------------------------------------------------------------------
*/
void
Td_DeletePdev(ttyPdev)
Td_Pdev ttyPdev; /* Pseudo-terminal to destroy. */
{
register PdevTerm *ptPtr = (PdevTerm *) ttyPdev;
/*
* Close the terminal first, so that hangups can be sent to
* processes.
*/
Td_Delete(ptPtr->term);
Pdev_Close(ptPtr->pdev);
unlink(ptPtr->pdevName);
free(ptPtr->pdevName);
free((char *) ptPtr);
}
/*
*----------------------------------------------------------------------
*
* PdevOpen --
*
* This procedure is called back by the Pdev module whenever
* a pseudo-terminal is being opened.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
PdevOpen(ptPtr, newStream, readBuffer, flags, procID, hostID,
uid, selectBitsPtr)
register PdevTerm *ptPtr; /* Our information about the pdev. */
Pdev_Stream *newStream; /* Service stream associated with the
* new open. */
char *readBuffer; /* Read buffer: not used here. */
int flags; /* Flags from open kernel call (not used). */
int procID; /* Process doing open (not used). */
int hostID; /* Host where process is running (not used). */
int uid; /* Effective user id of pid (not used). */
int *selectBitsPtr; /* Store select state of new stream here. */
{
int result;
Boolean true = TRUE;
ReturnStatus status;
newStream->clientData = (ClientData) ptPtr;
result = Td_Open(ptPtr->term, &ptPtr->selectState);
*selectBitsPtr = ptPtr->selectState;
status = Fs_IOControl(newStream->streamID, IOC_PDEV_WRITE_BEHIND,
sizeof(int), (Address) &true, 0, (Address) NULL);
if (status != SUCCESS) {
panic("PdevOpen couldn't enable write-behind: %s",
Stat_GetMsg(status));
}
return result;
}
/*
*----------------------------------------------------------------------
*
* PdevClose --
*
* This procedure is called back by the Pdev module when all of
* the streams corresponding to one "open" on a pseudo-terminal
* have now been closed.
*
* Results:
* Always returns zero.
*
* Side effects:
* State in the terminal is updated.
*
*----------------------------------------------------------------------
*/
static int
PdevClose(streamPtr)
Pdev_Stream *streamPtr; /* Service stream that is about to go away. */
{
Td_Close(((PdevTerm *) streamPtr->clientData)->term);
return 0;
}
/*
*----------------------------------------------------------------------
*
* PdevRead --
*
* This procedure is called back by the Pdev module whenever
* a client tries to read the pseudo-device associated with
* a terminal.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
PdevRead(streamPtr, readPtr, freeItPtr, selectBitsPtr, sigPtr)
Pdev_Stream *streamPtr; /* Service stream the client specified in its
* kernel call. */
Pdev_RWParam *readPtr; /* Read parameter block. Indicates size,
* buffer, plus various IDs */
Boolean *freeItPtr; /* Not used here. */
int *selectBitsPtr; /* Store new select state of terminal here. */
Pdev_Signal *sigPtr;
{
int result;
register PdevTerm *ptPtr = (PdevTerm *) streamPtr->clientData;
result = Td_GetCooked(ptPtr->term, readPtr->procID, readPtr->familyID,
&readPtr->length, readPtr->buffer, &sigPtr->signal,
&ptPtr->selectState);
*selectBitsPtr = ptPtr->selectState;
return result;
}
/*
*----------------------------------------------------------------------
*
* PdevWrite --
*
* This procedure is called back by the Pdev module whenever
* a client tries to write the pseudo-device associated with
* a terminal. Note: these writes are always asynchronous.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
PdevWrite(streamPtr, async, writePtr, selectBitsPtr, sigPtr)
Pdev_Stream *streamPtr; /* Service stream the client specified in its
* kernel call. */
int async; /* Non-zero means this is an asynchronous
* write request (should always be TRUE). */
Pdev_RWParam *writePtr; /* Write parameter block. Indicates size,
* offset, and buffer, among other things */
int *selectBitsPtr; /* Store new select state of terminal here. */
Pdev_Signal *sigPtr; /* Signal to return, if any */
{
register PdevTerm *ptPtr = (PdevTerm *) streamPtr->clientData;
int oldBits, result;
oldBits = ptPtr->selectState;
result = Td_PutCooked(ptPtr->term, &writePtr->length, writePtr->buffer,
&sigPtr->signal, &ptPtr->selectState);
if (ptPtr->selectState != oldBits) {
Pdev_EnumStreams(ptPtr->pdev, ChangeReady,
(ClientData) ptPtr->selectState);
}
*selectBitsPtr = ptPtr->selectState;
return result;
}
/*
*----------------------------------------------------------------------
*
* PdevIoctl --
*
* This procedure is called back by the Pdev module whenever
* a client tries to issue an ioctl on the pseudo-device associated
* with a terminal.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
PdevIoctl(streamPtr, ioctlPtr, selectBitsPtr, sigPtr)
Pdev_Stream *streamPtr; /* Service stream the client specified in its
* kernel call. */
Pdev_IOCParam *ioctlPtr; /* I/O control parameters */
int *selectBitsPtr; /* Store new select state of terminal here. */
Pdev_Signal *sigPtr; /* Returned signal, if any */
{
register PdevTerm *ptPtr = (PdevTerm *) streamPtr->clientData;
int result;
result = Td_ControlCooked(ptPtr->term, ioctlPtr->command,
ioctlPtr->format,
ioctlPtr->inBufSize, ioctlPtr->inBuffer,
&ioctlPtr->outBufSize, ioctlPtr->outBuffer,
&sigPtr->signal, &ptPtr->selectState);
*selectBitsPtr = ptPtr->selectState;
return result;
}
/*
*----------------------------------------------------------------------
*
* CookedProc --
*
* This procedure is called back by the Td module to inform
* us of various things happening on the cooked side of the
* terminal.
*
* Results:
* The return value is the number of bytes of output data
* stored at outBuffer (always 0 right now).
*
* Side effects:
* Depends on the command; read the code for details.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
CookedProc(ptPtr, command, inSize, inBuffer, outSize, outBuffer)
register PdevTerm *ptPtr; /* Information about the pseudo-device
* for the terminal. */
int command; /* Identifies control operation being
* invoked, e.g. TD_COOKED_SIGNAL. */
int inSize; /* Number of bytes of input data available
* to us. */
char *inBuffer; /* Pointer to input data. */
int outSize; /* Maximum number of bytes of output data
* we can return to caller. */
char *outBuffer; /* Area in which to store output data for
* caller. */
{
int result = 0;
switch (command) {
case TD_COOKED_SIGNAL:
(void) Pdev_EnumStreams(ptPtr->pdev, SendSignal,
(ClientData) inBuffer);
break;
case TD_COOKED_READS_OK:
if (!(ptPtr->selectState & FS_READABLE)) {
ptPtr->selectState |= FS_READABLE;
(void) Pdev_EnumStreams(ptPtr->pdev, ChangeReady,
(ClientData) ptPtr->selectState);
}
break;
case TD_COOKED_WRITES_OK:
if (!(ptPtr->selectState & FS_WRITABLE)) {
ptPtr->selectState |= FS_WRITABLE;
(void) Pdev_EnumStreams(ptPtr->pdev, ChangeReady,
(ClientData) ptPtr->selectState);
}
break;
}
return result;
}
/*
*----------------------------------------------------------------------
*
* ChangeReady --
*
* This procedure is called back by Pdev_EnumStreams in order
* to reset the readiness of all the streams associated with
* a terminal.
*
* Results:
* Always returns 0.
*
* Side effects:
* The stream's select state is updated to match.
*
*----------------------------------------------------------------------
*/
static int
ChangeReady(streamPtr, selectState)
Pdev_Stream *streamPtr; /* Information about the particular
* stream. */
int selectState; /* New select state for stream. */
{
ReturnStatus status;
status = Fs_IOControl(streamPtr->streamID, IOC_PDEV_READY,
sizeof(int), (Address) &selectState, 0, (Address) 0);
if (status != SUCCESS) {
panic("ChangeReady couldn't reset select state for pdev: %s",
Stat_GetMsg(status));
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* SendSignal --
*
* This procedure is called back by Pdev_EnumStreams in order
* to send a signal to the controlling process for a terminal.
*
* Results:
* Always returns 1 to abort the enumeration after 1 stream
* has been processed (there's no need to generate the signal
* more than once).
*
* Side effects:
* A signal is sent to the pseudo-device's controlling process (group).
*
*----------------------------------------------------------------------
*/
static int
SendSignal(streamPtr, sigInfoPtr)
Pdev_Stream *streamPtr; /* Information about the particular
* stream. */
Td_Signal *sigInfoPtr; /* Information about signal to send. */
{
ReturnStatus status;
Pdev_Signal sigInfo;
status = Compat_UnixSignalToSprite(sigInfoPtr->sigNum, &sigInfo.signal);
if (status != SUCCESS) {
panic("SendSignal couldn't translate signal %d", sigInfoPtr->sigNum);
}
sigInfo.code = 0;
/*
* Ignore errors in sending the signal: they could happen because
* the user set a non-existent process group.
*/
(void) Fs_IOControl(streamPtr->streamID, IOC_PDEV_SIGNAL_OWNER,
sizeof(sigInfo), (Address) &sigInfo, 0, (Address) 0);
return 1;
}
@
1.7
log
@Bogus extra parameter was causing selectBits to get garbaged in
kernel and making txinfo hang, among other things.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyPdev.c,v 1.6 89/06/15 15:09:37 ouster Exp $ SPRITE (Berkeley)";
d350 1
@
1.6
log
@Lint.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyPdev.c,v 1.5 89/06/03 16:47:26 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
d312 1
a312 1
Pdev_EnumStreams(ptPtr->pdev, ChangeReady, &sigPtr->signal,
@
1.5
log
@Several changes: TD_HANGUP is now TD_GOT_CARRIER and TD_LOST_CARRIER,
added TD_RAW_BAUD_RATE callback, changed TD_COOKED_SIGNAL to provide
both signal number and controlling process group.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyPdev.c,v 1.4 89/06/02 13:38:39 brent Exp Locker: ouster $ SPRITE (Berkeley)";
d265 1
a265 1
int result, sigNum;
d347 1
a347 1
int result, sigNum;
@
1.4
log
@Updated to new pseudo-device interface with signals
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/ttyPdev.c,v 1.3 89/04/20 10:24:21 ouster Exp Locker: brent $ SPRITE (Berkeley)";
d396 1
a396 1
(ClientData) *((int *) inBuffer));
d471 1
a471 1
SendSignal(streamPtr, signal)
d474 1
a474 1
int signal; /* Signal to send. */
d479 1
a479 1
status = Compat_UnixSignalToSprite(signal, &sigInfo.signal);
d481 1
a481 1
panic("SendSignal couldn't translate signal %d", signal);
@
1.3
log
@Removed log code: no longer needed.
@
text
@d18 1
a18 1
static char rcsid[] = "$Header: /a/newcmds/tty/RCS/ttyPdev.c,v 1.4 89/03/23 15:26:08 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
d256 1
a256 2
PdevRead(streamPtr, offset, procID, familyID, numBytesPtr, bufferPtr,
freeItPtr, selectBitsPtr)
d259 2
a260 8
int offset; /* Position within file; ignored. */
int procID; /* Name of reading process. */
int familyID; /* Process group to which procID belongs. */
int *numBytesPtr; /* Points to number of bytes wanted;
* overwritten with number of bytes actually
* supplied. */
char **bufferPtr; /* Pointer to pointer to buffer in which to
* store data. */
d263 1
d268 3
a270 5
result = Td_GetCooked(ptPtr->term, procID, familyID, numBytesPtr,
*bufferPtr, &sigNum, &ptPtr->selectState);
if (sigNum != 0) {
(void) kill(procID, sigNum);
}
d295 1
a295 2
PdevWrite(streamPtr, async, offset, procID, familyID, numBytesPtr,
buffer, selectBitsPtr)
d300 2
a301 8
int offset; /* Not used. */
int procID; /* Not used. */
int familyID; /* Not used. */
int *numBytesPtr; /* Points to number of bytes the client wants
* to write; overwritten with number of
* bytes actually accepted. */
char *buffer; /* Pointer to buffer containing data to be
* be written. */
d303 1
d306 1
a306 1
int oldBits, result, sigNum;
d309 2
a310 5
result = Td_PutCooked(ptPtr->term, numBytesPtr, buffer, &sigNum,
&ptPtr->selectState);
if (sigNum != 0) {
(void) kill(procID, sigNum);
}
d312 1
a312 1
Pdev_EnumStreams(ptPtr->pdev, ChangeReady, &sigNum,
d339 1
a339 2
PdevIoctl(streamPtr, command, procID, familyID, byteOrder, inSize, inBuffer,
outSizePtr, outBuffer, selectBitsPtr)
d342 1
a342 14
int command; /* Ioctl command (e.g. IOC_TTY_SETP). */
int procID; /* Not used. */
int familyID; /* Not used. */
int byteOrder; /* Identifies data format of host on which
* the client is running. */
int inSize; /* Number of bytes of data in inBuffer. */
char *inBuffer; /* Pointer to buffer containing input data
* for ioctl. */
int *outSizePtr; /* Pointer to maximum number of bytes of
* output data wanted by client. Gets
* overwritten with the amount supplied. */
char *outBuffer; /* Pointer to buffer in which to store
* output data. Guaranteed to have at
* least *outSizePtr bytes of space. */
d344 1
d349 4
a352 5
result = Td_ControlCooked(ptPtr->term, command, inSize, inBuffer,
outSizePtr, outBuffer, &sigNum, &ptPtr->selectState);
if (sigNum != 0) {
(void) kill(procID, sigNum);
}
@
1.2
log
@Slight improvement to tracing code.
@
text
@a48 30
* Temporary log to track down rlogin lock-up problem:
*/
typedef struct {
int operation; /* See #defines below. */
int selectState;
int otherData;
} LogEntry;
#define BEFORE_OPEN 1
#define AFTER_OPEN 2
#define BEFORE_READ 3
#define AFTER_READ 4
#define BEFORE_WRITE 5
#define AFTER_WRITE 6
#define BEFORE_IOCTL 7
#define AFTER_IOCTL 8
#define READS_OK 9
#define WRITES_OK 10
static LogEntry log[256];
static int logCurrent;
#define LOG(op, state, other) \
log[logCurrent].operation = (op); \
log[logCurrent].selectState = (state); \
log[logCurrent].otherData = (other); \
logCurrent = (logCurrent+1) & 0xff;
/*
a198 1
LOG(BEFORE_OPEN, ptPtr->selectState, 0);
a199 1
LOG(AFTER_OPEN, ptPtr->selectState, result);
a273 1
LOG(BEFORE_READ, ptPtr->selectState, *numBytesPtr);
a275 1
LOG(AFTER_READ, ptPtr->selectState, result);
a322 1
LOG(BEFORE_WRITE, ptPtr->selectState, *numBytesPtr);
a324 1
LOG(AFTER_WRITE, ptPtr->selectState, result);
a378 1
LOG(BEFORE_IOCTL, ptPtr->selectState, command);
a380 1
LOG(AFTER_IOCTL, ptPtr->selectState, result);
a429 1
LOG(READS_OK, ptPtr->selectState, 0);
a436 1
LOG(WRITES_OK, ptPtr->selectState, 0);
@
1.1
log
@Initial revision
@
text
@d468 1
a472 1
LOG(READS_OK, ptPtr->selectState, 0);
d476 1
a480 1
LOG(WRITES_OK, ptPtr->selectState, 0);
@